﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Media;
using System.Collections;

namespace SpaceInvaders
{
    class GameCode
    {
        //Variables and constants   
        private const int HEIGHT = 35;
        private const int WIDTH = 110;
        private static readonly Dictionary<int, string> ENEMY_SHAPES = new Dictionary<int, string> { { 10, "|-o-|" }, { 11, "(=0=)" }, { 12, "<>0<>" } };
        private static readonly Dictionary<int, int> ENEMY_SHIP_SCORES = new Dictionary<int, int> { { 10, 10 }, { 11, 20 }, { 12, 30 } };
        private const int ENEMY_SHIP_LENGTH = 5;
        private const int ENEMY_GAPS = 2;
        private const int TOTAL_ENEMIES = 55;

        private static int _lastEnemiesKilled = 0;
        private static int gameSpeed;
        private static int _enemiesKilled = 0;
        private static bool enemyGoLeft;
        private static bool stopEnemyMovement;
        private static int remainingEnemies;
        private static int enemyFieldLeft;
        private static int enemyFieldRight;
        private static int enemyFieldTop;
        private static int enemyFieldBottom;
        private static sbyte enemySpeed;

        private static sbyte enemyShotSpeed;
        private static List<Shots> enemyShots;
        private static int nextEnemyShot;
        static Random random = new Random();
        private static char drawEnemyShot;
        private static int enemyFireRateLow;
        private static int enemyFireRateHigh;

        private static string nickName;
        private static int currentScore;
        private static int livesRemaining;

        public static Ship ship;
        public static Saucer saucer;

        static int playerShotX;
        static int playerShotY;
        static bool playerShotExists;
        static char drawPlayerShot;

        static int[,] gameField;

        //Check if the current score is better then one of those in the top 10 file and if so updates the file.
        public static void SaveScore()
        {
            ArrayList scores = new ArrayList(10);
            string line = "";
            int lineCount = 0;

            try
            {
                StreamReader reader = new StreamReader("..\\..\\High.Score");
                //reads all scores a save them in a List
                
                while ((line = reader.ReadLine()) != null)
                {
                    int indexOfSplit = line.IndexOf(' ');
                    string points = line.Substring(0, indexOfSplit);
                    string name = line.Substring(indexOfSplit + 1);
                    string[] score = new string[] { points, name };
                    scores.Add(score);
                    lineCount++;
                }
                reader.Close();
                //Append new high score if they are less than 10
                int finalPos = 0;
                foreach (string[] scoreLines in scores)
                {
                    if (currentScore > int.Parse(scoreLines[0])) break;
                    finalPos++;
                    if (finalPos > 9) break;
                }
                scores.Insert(finalPos, new string[] { currentScore.ToString(), nickName });
                StreamWriter writer = new StreamWriter("..\\..\\High.Score");
                for (int i = 0; i < 10 && i < scores.Count; i++)
                {
                    writer.WriteLine(((string[])scores[i])[0] + " " + ((string[])scores[i])[1]);
                }
                writer.Close();
            }
            catch (SystemException)
            {
                Console.WriteLine("Could not write to high score file, delete it to resolve conflict.");
            }
        }


        //Plays a sound.
        public static void PlaySound(object info)
        {
            string path = (string)info;
            SoundPlayer sound = new SoundPlayer(path);
            sound.PlaySync();
        }

        //Changes the score.
        private static void ChangeScoreBy(int points)
        {
            currentScore += points;

            //print score at top-middle
            string scorestring = currentScore.ToString().PadLeft(7, '0');
            Console.SetCursorPosition((WIDTH / 2) - scorestring.Length, 0);
            Console.Write("SCORE\t" + scorestring);
        }

        //Removes one life from the player and checks if we get game over.
        private static void RemoveOneLife()
        {
            livesRemaining--;

            if (livesRemaining < 0)
            {
                SaveScore();
                DrawGameOverScreen();
                while (true)
                {
                    if (Console.KeyAvailable)
                    {
                        ConsoleKeyInfo keyInfo = Console.ReadKey(true);
                        while (Console.KeyAvailable)
                        {
                Console.ReadKey(true);
                        }
                        if (keyInfo.Key == ConsoleKey.Backspace)
                        {
                Engine();
            }
                    }
                }
            }

            //print the lives Icons ship Icon
            Console.SetCursorPosition(0, 0);
            Console.Write("                                   ");
            Console.SetCursorPosition(0, 0);
            Console.Write("LIVES ");
            Console.ForegroundColor = ConsoleColor.DarkGreen;
            for (int i = 0; i < livesRemaining; i++)
            {
                Console.Write(ship.GetShape());
            }
            Console.ResetColor();

            //print score at top-middle
            string scorestring = currentScore.ToString().PadLeft(7, '0');
            Console.SetCursorPosition((WIDTH / 2) - scorestring.Length, 0);
            Console.Write("SCORE\t" + scorestring);

        }

        //Draws the game over screen.
        private static void DrawGameOverScreen()
        {
            Console.Clear();
            string fail = "You have failed the Earth!";
            string enemiesGloating = "<>0<>  (=0=)  |-o-|  (00000)  |-o-|  (=0=)  <>0<>";
            string gameOverAlternative = "GAME OVER";
            string returnMainMenu = "Press 'BACKSPACE' key to return to Main Menu...";
            Console.SetCursorPosition(0, 7);
            Console.CursorLeft = (WIDTH / 2) - (fail.Length / 2);
            Console.WriteLine(fail);
            Console.WriteLine();
            Console.CursorLeft = (WIDTH / 2) - (enemiesGloating.Length / 2);
            Console.WriteLine(enemiesGloating);
            Console.WriteLine();
            string gameOver = @"../../game.over";
            try
            {
                StreamReader reader = new StreamReader(gameOver);
                Console.WriteLine();
                using (reader)
                {
                    string readerLine = reader.ReadLine();
                    while (readerLine != null)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.CursorLeft = (WIDTH / 2) - (readerLine.Length / 2);
                        Console.WriteLine(readerLine);
                        readerLine = reader.ReadLine();
                    }
                }
                Console.ResetColor();
                Console.WriteLine();
            }
            catch (Exception)
            {
                Console.CursorLeft = (WIDTH / 2) - (gameOverAlternative.Length / 2);
                Console.WriteLine(gameOverAlternative);
            }
            Console.SetCursorPosition(48, 5);
            Console.WriteLine("Your Score: {0}", currentScore);
            Console.SetCursorPosition(0, 26);
            Console.CursorLeft = (WIDTH / 2) - (returnMainMenu.Length / 2);
            Console.WriteLine(returnMainMenu);
        }

        //Loads the enemies initially on the screen.
        public static void LoadEnemies()
        {
            try
            {
                _enemiesKilled = 0;
                _lastEnemiesKilled = 0;
                StreamReader reader = new StreamReader("enemyPositions.txt");
                using (reader)
                {
                    enemyFieldTop = HEIGHT;
                    enemyFieldLeft = WIDTH;
                    enemyFieldRight = 0;
                    enemyFieldBottom = 0;
                    remainingEnemies = 0;
                    enemyGoLeft = true;

                    for (int row = 0; row < 35; row++)
                    {
                        string line = reader.ReadLine().Trim();
                        string[] numbers = line.Split(' ');
                        for (int col = 0; col < numbers.Length; col++)
                        {
                            int num = int.Parse(numbers[col]);
                            if (num != 0) gameField[row, col] = num;

                            if (num != 0)
                            {
                                if (col < enemyFieldLeft) enemyFieldLeft = col;
                                if (col + ENEMY_SHIP_LENGTH - 1 > enemyFieldRight) enemyFieldRight = col + ENEMY_SHIP_LENGTH - 1;
                                if (row < enemyFieldTop) enemyFieldTop = row;
                                if (row > enemyFieldBottom) enemyFieldBottom = row;

                                remainingEnemies++;

                                Console.SetCursorPosition(col, row);
                                Console.Write(ENEMY_SHAPES[num]);
                                for (int i = 1; i < ENEMY_SHIP_LENGTH; i++)
                                {
                                    gameField[row, col + i] = num;
                                }
                                col += ENEMY_SHIP_LENGTH;
                            }
                        }
                    }
                }
            }
            catch (SystemException e)
            {
                Console.SetCursorPosition(50, 15);
                Console.WriteLine("Enemies failed to load - enemy file corrupted.");
                Environment.Exit(0);
            }
        }

        //Moves the ship left or right;
        public static void ShipMovement()
        {
            if (Console.KeyAvailable)
            {
                ConsoleKeyInfo keyInfo = Console.ReadKey(true);
                while (Console.KeyAvailable)
                {
                    Console.ReadKey(true);
                }
                if (keyInfo.Key == ConsoleKey.LeftArrow)
                {
                    if (ship.GetX() > 1)   //check boundaries
                    {
                        ship.ClearShip();
                        ship.SetX(ship.GetX() - 1);
                        ship.DrawShip();
                    }
                }
                else if (keyInfo.Key == ConsoleKey.RightArrow)
                {
                    if (ship.GetX() < WIDTH - 1 - ship.GetShipLength()) //check boundaries  BUG at the end!
                    {
                        ship.ClearShip();
                        ship.SetX(ship.GetX() + 1);
                        ship.DrawShip();
                    }
                }
                if (keyInfo.Key == ConsoleKey.Spacebar && !playerShotExists && !stopEnemyMovement)
                {
                    playerShotX = ship.GetX() + ship.shape.Length / 2;
                    playerShotY = ship.GetY() - 1;
                    playerShotExists = true;
                    Thread laser = new Thread(GameCode.PlaySound);
                    laser.Start("Lazer.wav");
                }
                else if (keyInfo.Key == ConsoleKey.Backspace)
                {
                    QuitGame();
                }
                else if (keyInfo.Key == ConsoleKey.P)
                {
                    PauseGame();
                }
            }
        }

        //Moves the saucer
        public static void MoveSaucer()
        {  
            if (saucer != null && DateTime.Now.Millisecond % 3 == 0)
            {
                     
                    if (saucer.GetX() < WIDTH - 1 - saucer.shape.Length)
                    {
                        saucer.DrawSaucer();
                        saucer.SetX(saucer.GetX() + 1);
                        saucer.ClearSaucer();
                    }
                    else
                    {
                        saucer.RemoveSaucer();
                        saucer = null;
                    }
                   
            }
        }

        //Moves the players shot and calculates hits (if they occur)
        public static void MovePlayerShot()
        {
            if (gameField[playerShotY, playerShotX] >= 10 && gameField[playerShotY, playerShotX] <= 12)
            {
                ChangeScoreBy(ENEMY_SHIP_SCORES[gameField[playerShotY, playerShotX]]);
                PlayerShotEnemyCollision();
                playerShotExists = false;
                return;
            }
            Console.SetCursorPosition(playerShotX, playerShotY);
            Console.Write(' ');
            playerShotY -= 1;
            Console.SetCursorPosition(playerShotX, playerShotY);
            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.Write(drawPlayerShot);
            Console.ResetColor();
            
            if (playerShotY == 1 || CollisionPlayerShotWithCover())
            {
                Console.SetCursorPosition(playerShotX, playerShotY);
                Console.Write(' ');
                playerShotExists = false;
            }
            else if (gameField[playerShotY, playerShotX] >= 10 && gameField[playerShotY, playerShotX] <= 12)
            {
                ChangeScoreBy(ENEMY_SHIP_SCORES[gameField[playerShotY, playerShotX]]);
                PlayerShotEnemyCollision();
                playerShotExists = false;
            }
            else if (CollisionPlayerShotWithSaucer()) 
            {
                saucer.KillSaucer();
                ChangeScoreBy(saucer.GetScore());
                saucer.RemoveSaucer();
                saucer = null;
                Saucer.scoreMultiplier ++;
            }
            else if (CollisionPlayerShotWithEnemyShot())
            {
                Console.SetCursorPosition(playerShotX, playerShotY);
                Console.Write('X');
                Console.SetCursorPosition(playerShotX, playerShotY);
                Console.Write(' ');
                playerShotExists = false;
            }
        }

        
        // Collision player shot with enemy shot
        static bool CollisionPlayerShotWithEnemyShot()
        {
            if (!playerShotExists) return false;

            foreach (var shot in enemyShots)
            {

                if (playerShotX != shot.X) return false;

                if (playerShotX == shot.X)
                {
                    if (playerShotY != shot.Y) return false;
                    else
                    {
                        enemyShots.Remove(shot);
                        return true;
                    }
                }
            }
            return false;
        }

        // Collision player shot with enemy shot
        static bool CollisionPlayerShotWithEnemyShot(Shots shot)
        {
            if (!playerShotExists) return false;

            if (playerShotX != shot.X) return false;

            if (playerShotX == shot.X)
            {
                if (playerShotY != shot.Y) return false;
                else
                {
                    return true;
                }
            }
            return false;
        }

        // Collision player shot with mystery ship
        static bool CollisionPlayerShotWithSaucer()
        {
            if (saucer != null)
            {
                if (!playerShotExists) return false;

                if (playerShotY != saucer.GetY()) return false;

                if (playerShotX < saucer.GetX()) return false;

                if (playerShotX >= (saucer.GetX() + saucer.shape.Length)) return false;

                return true;
            }
            else
            {
                return false;
            }
        }

        // Collision of player shot with cover
        static bool CollisionPlayerShotWithCover()
        {
            if (gameField[playerShotY, playerShotX] == 1)
            {
                gameField[playerShotY, playerShotX] = 0;
                return true;
            }
            return false;
        }

        // Collision of enemy shot with cover
        static bool CollisionEnemyShotWithCover(Shots shot)
        {
            if (gameField[shot.Y, shot.X] == 1)
            {
                gameField[shot.Y, shot.X] = 0;
                return true;
            }
            return false;
        }

        //Inneficient placeholder TO DO - Fix.
        static void UpdateEnemyField()
        {
            int tempLeft = WIDTH,
                tempRight = 0,
                tempTop = HEIGHT,
                tempBot = 0;
            for (int i = enemyFieldTop; i <= enemyFieldBottom; i++)
            {
                for (int j = enemyFieldLeft; j <= enemyFieldRight; j++)
                {
                    if (gameField[i, j] != 0)
                    {
                        if (j < tempLeft) tempLeft = j;
                        if (j > tempRight) tempRight = j;
                        if (i < tempTop) tempTop = i;
                        if (i > tempBot) tempBot = i;
                    }
                }
            }
            enemyFieldLeft = tempLeft;
            enemyFieldRight = tempRight;
            enemyFieldTop = tempTop;
            enemyFieldBottom = tempBot;
        }

        //Speeds up enemies when they get destroyed
        static void UpdateEnemySpeed()
        {
            if (((TOTAL_ENEMIES - remainingEnemies) % 5 == 0) && remainingEnemies >= 5)
            {
                enemySpeed -= 1;
                enemyFireRateLow--;
                enemyFireRateHigh--;
            }
            else if (remainingEnemies < 5)
            {
                enemySpeed -= 1;
                enemyFireRateLow--;
                enemyFireRateHigh--;
            }
        }

        //Needs victory logic.
        static void PlayerShotEnemyCollision()
        {
            _enemiesKilled++;
            int temp = playerShotX;
            while (gameField[playerShotY, temp] != 0) temp--;

            DrawDestruction(temp + 1, playerShotY);
            for (int i = temp + 1; i < temp + 1 + ENEMY_SHIP_LENGTH; i++)
            {
                gameField[playerShotY, i] = 0;
            }

            UpdateEnemyField();
            remainingEnemies--;
            UpdateEnemySpeed();
            //Victory logic here.
            if (remainingEnemies == 0)
            {
                ChangeScoreBy(100 * livesRemaining);
                SaveScore();
                DrawVictoryScreen();
                while (true)
                {
                    if (Console.KeyAvailable)
                    {
                        ConsoleKeyInfo keyInfo = Console.ReadKey(true);
                        while (Console.KeyAvailable)
                        {
                Console.ReadKey(true);
                        }
                        if (keyInfo.Key == ConsoleKey.Backspace)
                        {
                Engine();
            }
        }
                }
            }
        }

        //Draw the destruction of an enemy ship.
        static void DrawDestruction(int x, int y)
        {  
            stopEnemyMovement = true;
            Console.SetCursorPosition(x, y);
            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.Write(new string('\u2592', ENEMY_SHIP_LENGTH));
            Console.Beep(1000, 350);
            Console.SetCursorPosition(x, y);
            Console.Write(new string(' ', ENEMY_SHIP_LENGTH));
            Console.ResetColor();
            stopEnemyMovement = false;   
        }

        // Draw victory screen
        static void DrawVictoryScreen()
        {
            string wellDone = "W E L L   D O N E   E A R T H L I N G";
            string thisTime = "T H I S   T I M E   Y O U   W I N";
            string returnMainMenu = "Press 'BACKSPACE' key to return to Main Menu...";
            Console.SetCursorPosition(0, 8);
            Console.CursorLeft = (WIDTH / 2) - (wellDone.Length / 2);
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(wellDone);
            Console.ResetColor();
            Console.SetCursorPosition(0, 10);
            Console.CursorLeft = (WIDTH / 2) - (thisTime.Length / 2);
            Console.WriteLine(thisTime);           
            Console.SetCursorPosition(0, 16);
            Console.CursorLeft = (WIDTH / 2) - (returnMainMenu.Length / 2);
            Console.WriteLine(returnMainMenu);
        }

        //Moves the positions in the gamefield
        public static void UpdateGameField(int left, int right, int top, int bottom, int horizontal = 0, int vertical = 0)
        {
            if (horizontal > 0)
            {
                for (int i = top; i <= bottom; i++)
                {
                    for (int j = right; j >= left - 1; j--)
                    {
                        if (gameField[i, j] != 0 && gameField[i, j - 1] == 0) gameField[i, j] = 0;
                        else if (gameField[i, j] != 0 && gameField[i, j + 1] == 0) gameField[i, j + 1] = gameField[i, j];
                    }
                }
            }
            else if (horizontal < 0)
            {
                for (int i = top; i <= bottom; i++)
                {
                    for (int j = left; j <= right + 1; j++)
                    {
                        if (gameField[i, j] != 0 && gameField[i, j - 1] == 0) gameField[i, j - 1] = gameField[i, j - 1] = gameField[i, j];
                        else if (gameField[i, j] != 0 && gameField[i, j + 1] == 0) gameField[i, j] = 0;
                    }
                }
            }
            if (vertical < 0)
            {
                for (int i = bottom; i >= top - 1; i--)
                {
                    for (int j = 0; j < WIDTH; j++)
                    {
                        gameField[i, j] = gameField[i - 1, j];
                    }
                }
            }
        }
        //Moves the enemies
        public static void MoveEnemies()
        {
            if (playerShotExists)
            {
                Console.SetCursorPosition(playerShotX, playerShotY);
                Console.Write(" ");
            }
            foreach (var shot in enemyShots)
            {   
                Console.SetCursorPosition(shot.X, shot.Y);
                Console.Write(" ");
            }
            if (enemyGoLeft && enemyFieldLeft > 1)
            {
                if (enemyFieldBottom == HEIGHT - 2)
                {
                    livesRemaining = 0;
                    RemoveOneLife();
                }   
                Console.MoveBufferArea(enemyFieldLeft, enemyFieldTop, (enemyFieldRight - enemyFieldLeft + 1), (enemyFieldBottom - enemyFieldTop + 1), enemyFieldLeft - 1, enemyFieldTop);
                enemyFieldLeft--;
                enemyFieldRight--;
                UpdateGameField(enemyFieldLeft, enemyFieldRight, enemyFieldTop, enemyFieldBottom, -1);
            }
            else if (enemyGoLeft)
            {
                Console.MoveBufferArea(enemyFieldLeft, enemyFieldTop, (enemyFieldRight - enemyFieldLeft + 1), (enemyFieldBottom - enemyFieldTop + 1), enemyFieldLeft, enemyFieldTop + 1);
                enemyFieldTop++;
                enemyFieldBottom++;
                UpdateGameField(enemyFieldLeft, enemyFieldRight, enemyFieldTop, enemyFieldBottom, 0, -1);
                enemyGoLeft = false;
            }
            else if (enemyFieldRight < WIDTH - 2)
            {
                Console.MoveBufferArea(enemyFieldLeft, enemyFieldTop, (enemyFieldRight - enemyFieldLeft + 1), (enemyFieldBottom - enemyFieldTop + 1), enemyFieldLeft + 1, enemyFieldTop);
                enemyFieldLeft++;
                enemyFieldRight++;
                UpdateGameField(enemyFieldLeft, enemyFieldRight, enemyFieldTop, enemyFieldBottom, 1);
            }
            else
            {
                if (enemyFieldBottom == HEIGHT - 2)
                {
                    livesRemaining = 0;
                    RemoveOneLife();
                }   
                Console.MoveBufferArea(enemyFieldLeft, enemyFieldTop, (enemyFieldRight - enemyFieldLeft + 1), (enemyFieldBottom - enemyFieldTop + 1), enemyFieldLeft, enemyFieldTop + 1);
                enemyFieldTop++;
                enemyFieldBottom++;
                UpdateGameField(enemyFieldLeft, enemyFieldRight, enemyFieldTop, enemyFieldBottom, 0, -1);
                enemyGoLeft = true;
            }
            if (playerShotExists)
            {
                Console.SetCursorPosition(playerShotX, playerShotY);
                Console.Write(drawPlayerShot);
            }
            foreach (var shot in enemyShots)
            {
                if (gameField[shot.Y, shot.X] != 0) shot.Y++;
                Console.SetCursorPosition(shot.X, shot.Y);
                Console.Write(drawEnemyShot);
            }
        }

        // Generate random enemy shots
        public static void GenerateRandomEnemyShot() 
        {
            int y = enemyFieldBottom;
            if (y >= HEIGHT - 2) return; 
            int x = random.Next(enemyFieldLeft, enemyFieldRight);
            List<int> fieldValues = new List<int>();
            fieldValues.Add(10); fieldValues.Add(11); fieldValues.Add(12);

            while (!fieldValues.Contains(gameField[y, x]))
            {
                if (y <= enemyFieldTop)
                {
                    x++;
                    y = enemyFieldBottom;
                    if (x > 109) return; //Necessary to solve a bug when only a single row of enemies remain.
                }
                y--;
            }

            int checkLowerMatchesY = enemyFieldBottom;
            while (checkLowerMatchesY > y)
            {
                if (fieldValues.Contains(gameField[checkLowerMatchesY, x]))
                {
                    y = checkLowerMatchesY;
                    break;
                }
                checkLowerMatchesY--;
            }

            y += 1;
            enemyShots.Add(new Shots(x, y));
        }

        //Moves the enemies shots and calculates hits (if they occur)
        public static void MoveEnemyShots()
        {
            List<Shots> shotsToRemove = new List<Shots>();
            foreach (var shot in enemyShots)
            {
                Console.ForegroundColor = ConsoleColor.White;
                Console.SetCursorPosition(shot.X, shot.Y);
                Console.Write(' ');
                shot.Y += 1;
                if (CollisionEnemyShotWithPlayerShip(shot))
                {
                    shotsToRemove.Add(shot);
                    Console.Beep(1500, 450);
                    RemoveOneLife();
                }
                else if (shot.Y == 34 || CollisionEnemyShotWithCover(shot))
                {
                    Console.SetCursorPosition(shot.X, shot.Y);
                    Console.Write(' ');
                    shotsToRemove.Add(shot);
                }
                else if (CollisionPlayerShotWithEnemyShot(shot))
                {
                    Console.SetCursorPosition(playerShotX, playerShotY);
                    Console.Write(' ');
                    playerShotExists = false;
                    shotsToRemove.Add(shot);
                }
                else
                {
                    Console.SetCursorPosition(shot.X, shot.Y);
                    Console.Write(drawEnemyShot);
                    Console.ResetColor();
                }
            }
            foreach (var shot in shotsToRemove)
            {
                enemyShots.Remove(shot);
            }
        }

        //Detects if the player ship has been hit
        public static bool CollisionEnemyShotWithPlayerShip(Shots shot)
        {
            if (shot.Y != ship.GetY()) return false;
            if (shot.X < ship.GetX()) return false;
            if (shot.X >= ship.GetX() + ship.shape.Length) return false;

            return true;
        }

        // Initialize cover
        static void InitialCover()
        {
            StreamReader reader = new StreamReader("fieldofcover.txt");
            using (reader)
            {
                for (int i = 0; i < WIDTH; i++)
                {
                    string[] currentLine = reader.ReadLine().Split(' ');

                    for (int j = 0; j < HEIGHT; j++)
                    {
                        if (gameField[j, i] == 0) gameField[j, i] = int.Parse(currentLine[j]);
                    }
                }
            }
        }

        //Draws the cover tiles on the screen.
        public static void DrawCover()
        {
            for (int i = 0; i < gameField.GetLength(0); i++)
            {
                for (int j = 0; j < gameField.GetLength(1); j++)
                {
                    if (gameField[i, j] == 1)
                    {
                        Console.ForegroundColor = ConsoleColor.DarkGreen;
                        Console.SetCursorPosition(j, i);
                        Console.Write("*");
                        Console.ResetColor();
                    }
                }
            }
        }

        // Quit the game
        public static void QuitGame()
        {
            StopGameInstructions(true);

            while (true)
            {
                if (Console.KeyAvailable)
                {
                    ConsoleKeyInfo keyInfo = Console.ReadKey(true);
                    while (Console.KeyAvailable)
                    {
                        Console.ReadKey(true);
                    }
                    if (keyInfo.Key == ConsoleKey.N)
                    {
                        StopGameInstructions(false);
                        ChangeScoreBy(0);
                        return;
                    }
                    if (keyInfo.Key == ConsoleKey.Y)
                    {
                        Engine();
                    }
                }
            }
        }

        // Stop the game and return to main menu
        public static void StopGameInstructions( bool show)
        {
            string returnToMain = ">>> ARE YOU SURE YOU WANT TO QUIT: 'Y' / 'N' <<<";
            if (show)
            {
                Console.SetCursorPosition(((WIDTH / 2) - (returnToMain.Length / 2)), 0);
                Console.Write(returnToMain);
            }
            else
            {
                Console.SetCursorPosition(((WIDTH / 2) - (returnToMain.Length / 2)), 0);
                Console.Write("                                                ");
            }
        }

        //Pauses the game.
        public static void PauseGame()
        {
            ResumeInstructions(true);
            
            while (true)
            {
                if (Console.KeyAvailable)
                {
                    ConsoleKeyInfo keyInfo = Console.ReadKey(true);
                    while (Console.KeyAvailable)
                    {
                        Console.ReadKey(true);
                    }
                    if (keyInfo.Key == ConsoleKey.R)
                    {
                        ResumeInstructions(false);
                        ChangeScoreBy(0);
                        return;
                    }
                    if (keyInfo.Key == ConsoleKey.Backspace)
                    {
                        Engine();
                    }
                }
            }            
        }

        //Resumes the game.
        private static void ResumeInstructions(bool show)
        {
            string resumePlay = ">>>PRESS 'R' TO RESUME PLAY OR 'BACKSPACE' TO QUIT<<<";
            if (show)
            {
                Console.SetCursorPosition(((WIDTH / 2) - (resumePlay.Length / 2)), 0);
                Console.Write(resumePlay);
            }
            else
            {
                Console.SetCursorPosition(((WIDTH / 2) - (resumePlay.Length / 2)), 0);
                Console.Write("                                                     ");
            }

        }

        //Loads the initial screen once the game starts.
        public static void LoadScreen()
        {
            ship = new Ship();

            gameField = new int[HEIGHT, WIDTH];
            Console.Clear();
            LoadEnemies();
            ship.DrawShip();
            InitialCover();
            DrawCover();          
            saucer = null;

            currentScore = 0;
            ChangeScoreBy(0);
            livesRemaining = 4;
            RemoveOneLife();

            drawPlayerShot = '\u001E';
            playerShotExists = false;
            stopEnemyMovement = false;
            gameSpeed = 25;
            enemySpeed = 14; //default 14
            enemyShotSpeed = 1; //default 1
            enemyFireRateLow = 45; //default 45
            enemyFireRateHigh = 20; //default 20

            drawEnemyShot = '\u001F';
            nextEnemyShot = random.Next(enemyFireRateHigh, enemyFireRateLow);
            
            enemyShots = new List<Shots>();
        }

        //Starts the game.
        public static void StartGame()
        {
            nickName = string.Empty;
            while (nickName ==string.Empty)
            {
                Console.CursorVisible = true;
                Console.SetCursorPosition(35, 16);
                Console.Write("Enter Nickname: ");
                nickName = Console.ReadLine().Trim();
                Console.CursorVisible = false;
            }

            LoadScreen();
            sbyte playerSpeed = 1;
            sbyte enemyMovement = enemySpeed;
            sbyte saucerCounter = 4;
            sbyte moveShot = enemyShotSpeed;
            
            while (true)
            {
                // Check Score, Change Level
                // Move Alien Ships Left and Right
                // Alien Ships Shoot. (new thread)?

                // Draw/Update Cover
                // Collision Detection
                if (saucer == null && _enemiesKilled % 10 == 0 && _lastEnemiesKilled != _enemiesKilled)//for testing purposes only
                {
                    _lastEnemiesKilled = _enemiesKilled;
                     
                    saucer = new Saucer();

                }

                if (playerSpeed == 0) ShipMovement();
                if (enemyMovement == 0 && !stopEnemyMovement) MoveEnemies();
                if (playerShotExists) MovePlayerShot();
                if (nextEnemyShot == 0) GenerateRandomEnemyShot();
                if (enemyShots.Count > 0 && moveShot == 0) MoveEnemyShots();

                if (saucer != null) { MoveSaucer(); }

                if (--playerSpeed == -1) playerSpeed = 1;
                if (--enemyMovement == -1) enemyMovement = enemySpeed;
                if (--saucerCounter == -1) saucerCounter = 5;
                if (enemyShots.Count > 0 && --moveShot == -1) moveShot = enemyShotSpeed;
                if (--nextEnemyShot == -1) nextEnemyShot = random.Next(enemyFireRateHigh, enemyFireRateLow);

                System.Threading.Thread.Sleep(gameSpeed);
            }
        }

        //Print the starting menu
        public static void PrintMenu()
        {
            Console.Clear();
            string line = "************ SPACE INVADERS ************";
            string logoPath = @"../../lo.go";
            try
            {
                StreamReader logoSR = new StreamReader(logoPath);
                Console.WriteLine();
                using (logoSR)
                {
                    string readerLine = logoSR.ReadLine();
                    while (readerLine != null)
                    {
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.CursorLeft = (WIDTH / 2) - (readerLine.Length / 2);
                        Console.WriteLine(readerLine);
                        readerLine = logoSR.ReadLine();
                    }
                }
                Console.ResetColor();
                Console.WriteLine();
            }
            catch (Exception)
            {
                Console.CursorLeft = (WIDTH / 2) - (line.Length / 2);
                Console.WriteLine(line);
            }
            Console.WriteLine(new string('-', 110));
            line = "3. View High Scores";
            Console.CursorLeft = (WIDTH / 2) - (line.Length / 2);
            Console.WriteLine("1. Start Game");
            Console.CursorLeft = (WIDTH / 2) - (line.Length / 2);
            Console.WriteLine("2. Controls");
            Console.CursorLeft = (WIDTH / 2) - (line.Length / 2);
            Console.WriteLine("3. View High Scores");
            Console.CursorLeft = (WIDTH / 2) - (line.Length / 2);
            Console.WriteLine("4. Score Board");
            Console.CursorLeft = (WIDTH / 2) - (line.Length / 2);
            Console.WriteLine("5. Exit Game");
            Console.WriteLine();
            Console.CursorLeft = (Console.WindowWidth / 2);
        }

        // Controls menu
        public static void Controls()
        {
            string ControlsTitle = "Keyboard Controls:";
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length / 2);
            Console.WriteLine(ControlsTitle);
            Console.WriteLine();
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length / 2);
            Console.WriteLine("\"Left Arrow\"   -  move player ship to the left");
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length / 2);
            Console.WriteLine("\"Right Arrow\"  -  move player ship to the right");
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length / 2);
            Console.WriteLine("\"Spacebar\"     -  shoot at enemy ships");
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length / 2);
            Console.WriteLine("\"P\"            -  pause the game");
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length / 2);
            Console.WriteLine("\"R\"            -  resume the game");
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length / 2);
            Console.WriteLine("\"Backspace\"    -  quit the game");
            Console.WriteLine();
            string pressSpace = "Press 'SPACE' to return to Main menu";
            Console.WriteLine();
            Console.CursorLeft = (WIDTH/2) - (pressSpace.Length/2);
            Console.WriteLine(pressSpace);

            do
            {
                if (Console.ReadKey(true).Key == ConsoleKey.Spacebar)
                {
                    Engine();
                }
            } while (true);     
        }

        //Highscores menu:
        public static void HighScores()
        {

            string filename = @"..\..\High.score";
            string HighScoreTitle = "Current Top 3 High Scores:";
            Console.CursorLeft = (WIDTH / 2) - (HighScoreTitle.Length / 2);
            Console.WriteLine(HighScoreTitle);
            Console.WriteLine();
            try
            {
                StreamReader reader = new StreamReader(filename);
                using (reader)
                {
                    for (int counter = 1; counter < 11; counter++)
                    {
                        string line = reader.ReadLine();
                        if (line != null)
                        {
                        int separatorIndex = line.IndexOf(' ');
                            string points = line.Substring(0, separatorIndex);
                            string nick = line.Substring(separatorIndex + 1);
                        string scoreLine = string.Format("{0} - - - - - {1,5}", nick, points);
                            Console.CursorLeft = (WIDTH / 2) - (scoreLine.Length / 2);
                        Console.WriteLine("{0,-3} {1}", counter + ".", scoreLine);
                        }
                        else break;
                    }
                }
            }

            catch (SystemException e)
            {
                Console.WriteLine("Error loading High Scores!");
            }
            string pressSpace = "Press 'SPACE' to return to Main menu";
            Console.WriteLine();
            Console.CursorLeft = (WIDTH/2) - (pressSpace.Length/2);
            Console.WriteLine(pressSpace);

            do
            {
                if (Console.ReadKey(true).Key == ConsoleKey.Spacebar)
                {
                    Engine();
                }
            } while (true);
        }

        //Score board - displays the score syste in Space Invaders
        public static void ScoreBoard()
        {
            string ControlsTitle = "Score Board:";
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length / 2);
            Console.WriteLine(ControlsTitle);
            Console.WriteLine();
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length);
            Console.WriteLine("|-o-|   = 10 POINTS!");
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length);
            Console.WriteLine("(=0=)   = 20 POINTS!");
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length);
            Console.WriteLine("<>0<>   = 30 POINTS!");
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length);
            Console.ForegroundColor = ConsoleColor.Red;
            Console.Write("(00000)");
            Console.ResetColor();
            Console.WriteLine(" = 50-250 consecutive kills give more POINTS! ");
            Console.CursorLeft = (WIDTH / 2) - (ControlsTitle.Length);
            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.Write(new Ship().GetShape());
            Console.ResetColor();
            Console.WriteLine(" = 100 POINTS for every extra life upon winning! ");


            string pressSpace = "Press 'SPACE' to return to Main menu";
            Console.WriteLine();
            Console.CursorLeft = (WIDTH / 2) - (pressSpace.Length / 2);
            Console.WriteLine(pressSpace);

            do
            {
                if (Console.ReadKey(true).Key == ConsoleKey.Spacebar)
                {
                    Engine();
                }
            } while (true);
        }

        //Starts the program
        public static void Engine()
        {
            PrintMenu();

            char choice = '0';
            while (choice < '1' || choice > '5')
            {
                Console.CursorLeft--;
                choice = Console.ReadKey(true).KeyChar;
            }

            // Put this in a loop, add input check. Add GoBack function for View Scores
            switch (choice)
            {
                case '1': StartGame();
                    break;
                case '2': Controls();
                    break;
                case '3': HighScores();
                    break;
                case '4': ScoreBoard();
                    break;
                case '5': Environment.Exit(0);
                    break;
            }
        }

        //Setups the console for use by the program
        public static void ConsoleSetup()
        {
            Console.WindowHeight = HEIGHT;
            Console.WindowWidth = WIDTH;
            Console.BufferHeight = Console.WindowHeight;
            Console.BufferWidth = Console.WindowWidth;
            Console.CursorVisible = false;
            Console.Title = "Space Invaders";
            ConsoleUtils.CenterConsole();
        }

        static void Main()
        {
            ConsoleSetup();
            Engine();
        }

    }
}